package com.dingreading.cloud.admin.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.RichTextStringData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.dingreading.cloud.admin.dto.*;
import com.dingreading.cloud.admin.dto.vo.CallNameVoV2;
import com.dingreading.cloud.admin.dto.vo.LessonVO;
import com.dingreading.cloud.admin.dto.vo.LessonVoV3;
import com.dingreading.cloud.admin.entity.CaCallNames;
import com.dingreading.cloud.admin.entity.CaScheduleLesson;
import com.dingreading.cloud.admin.feign.SomsFeignService;
import com.dingreading.cloud.admin.service.CaCallNamesService;
import com.dingreading.cloud.admin.service.CaScheduleLessonService;
import com.dingreading.cloud.admin.service.CmordersService;
import com.dingreading.cloud.admin.util.ScheduleUtil;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.excel.ExcelHandler;
import com.dingreading.cloud.common.util.excel.RowBean;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/system/scheduleLesson")
@Api(tags = "总部-活动记录管理")
public class CaScheduleLessonController {

    @Resource
    private CaScheduleLessonService scheduleLessonService;
    @Resource
    private CaCallNamesService callNameService;
    @Resource
    private CmordersService cmordersService;
    @Resource
    private SomsFeignService somsFeignService;


    @ApiOperation(value = "分页列表")
    @PostMapping(value = "/pageList")
    public R<Object> pageList(
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid", required = false) String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid", required = false) String storeUid,
            @ApiParam(value = "服务名称/主讲导读") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "活动状态 -1.已取消 0.未进行 1.已进行 2.已完成") @RequestParam(value = "status", required = false) Integer status,
            @ApiParam(value = "活动开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "活动结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) {
        Page<CaScheduleLessonDto> page = scheduleLessonService.pageListV3(
                pageUtil, corpUid, storeUid, keyword, status,
                null, null, null, null, null, null, null, beginDate, endDate
        );

        long total = page.getTotalRow();
        List<CaScheduleLessonDto> list = page.getRecords();

        if (CollectionUtils.isNotEmpty(list)) {
            List<String> scheduledUids = list.stream().map(CaScheduleLessonDto::getScheduleUid).distinct().collect(Collectors.toList());
            List<CaTeacherDto> teachers = somsFeignService.getTeachersByScheduleUids(scheduledUids);
            // 获取导读
            ScheduleUtil.listSetTeachers(list, teachers);
        }

        PageBeanDto data = new PageBeanDto();
        data.setTotal(total);
        data.setList(list);
        return R.ok(data);
    }


    @ApiOperation(value = "获取活动的已点名记录")
    @PostMapping(value = "/getCallNames", produces = "application/json; charset=UTF-8")
    public R<Object> getCallNames(
            @ApiParam(value = "活动uid") @RequestParam(value = "lessonUid") String lessonUid
    ) throws Exception {
        CaScheduleLesson lesson = scheduleLessonService.getLessonInfo(null, lessonUid);
        if (null == lesson)
            return R.fail("活动获取失败");
        String lessonStoreUid = lesson.getStoreUid();
        if (lesson.getStatus().equals(-1)) {
            List<CallMemberDto> members = scheduleLessonService.getClassMemberAndCallMember(lessonStoreUid, lesson.getClassId(), lessonUid);
            for (CallMemberDto member : members) {
                member.setHourTypeName("");
            }
            return R.ok(members);
        } else {
            List<CaCallNamesDto> list = callNameService.getLessonCallNameDtos(lessonStoreUid, lessonUid);
            return R.ok(list);
        }
    }


    @ApiOperation(value = "获取自营门店会员的活动点名记录")
    @PostMapping(value = "/getSelfMemberCallNames", produces = "application/json; charset=UTF-8")
    public void getSelfMemberCallNames(
            HttpServletResponse response,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate,
            @ApiParam(value = "服务名称") @RequestParam(value = "productName", required = false) String productName
    ) throws Exception {
        // 自营门店公司uid
        String corpUid = AccountUtil.SELF_CORP_UID;
        List<CaCallNames> list = callNameService.getMemberCallList(corpUid, beginDate, endDate, productName);

        List<CallNameVoV2> voList = new ArrayList<>();
        int firstStartRow = 1;
        int firstEndRow = 0;
        // 需要合并的行号
        List<RowBean> firstRows = new ArrayList<>();
        // 需要合并的列号
        List<Integer> firstColumns = Lists.newArrayList(0, 1);

        if (CollectionUtils.isNotEmpty(list)) {
            LinkedHashMap<String, List<CaCallNames>> map = list.stream().collect(Collectors.groupingBy(CaCallNames::getMemberUid, LinkedHashMap::new, Collectors.toList()));
            for (Map.Entry<String, List<CaCallNames>> entry : map.entrySet()) {
                String key = entry.getKey();
                List<CaCallNames> callList = entry.getValue();

                firstEndRow += callList.size();
                // 合并必须包含2个或更多单元格
                if (firstStartRow != firstEndRow)
                    firstRows.add(new RowBean(firstStartRow, firstEndRow));
                firstStartRow += callList.size();

                int lessonNum = callList.size();

                for (int i = 0; i < callList.size(); i++) {
                    CaCallNames call = callList.get(i);
                    CallNameVoV2 vo = new CallNameVoV2();
                    vo.setMemberName(call.getMemberName());
                    vo.setLessonNum(lessonNum);
                    vo.setLessonOrder("第" + (i + 1) + "次课");
                    vo.setStoreName(call.getStoreName());
                    vo.setTeachDate(call.getTeachDate());
                    vo.setProductName(call.getProductName());
                    vo.setStageName(call.getStageName());
                    vo.setTeacherName(call.getTeacherName());
                    vo.setStudentTypeName(call.getStudentTypeName());

                    WriteCellData<String> richCallStatus = new WriteCellData<>();
                    richCallStatus.setType(CellDataTypeEnum.RICH_TEXT_STRING);
                    vo.setCallStatusName(richCallStatus);
                    RichTextStringData textStringDataCallStatus = new RichTextStringData();
                    richCallStatus.setRichTextStringDataValue(textStringDataCallStatus);
                    // 字体样式
                    WriteFont writeFont = new WriteFont();
                    // 字体大小
                    writeFont.setFontHeightInPoints((short) 14);
                    short fontColor = IndexedColors.RED.getIndex();
                    if (null != call.getCallStatus())
                        if (call.getCallStatus().equals(1) || call.getCallStatus().equals(2)) {
                            fontColor = IndexedColors.GREEN.getIndex();
                        }
                    // 字体颜色
                    writeFont.setColor(fontColor);
                    String csName = StringUtils.isNotBlank(call.getCallStatusName()) ? call.getCallStatusName() : "";
                    textStringDataCallStatus.setTextString(csName);
                    textStringDataCallStatus.applyFont(writeFont);

                    if (call.getCloseTime() != null)
                        vo.setCloseTime(DateUtil.getDefaultTimeStr(call.getCloseTime()));

                    voList.add(vo);
                }
            }
        }

        String fileName = "自营门店会员活动记录" + beginDate + "至" + endDate;
        ExcelHandler.exportMergeExcel(response, voList, CallNameVoV2.class, fileName, "自营门店会员活动记录", firstRows, firstColumns);
    }


    @ApiOperation(value = "导出查询的活动记录")
    @PostMapping(value = "/exportList", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportList(
            HttpServletResponse response,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid", required = false) String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid", required = false) String storeUid,
            @ApiParam(value = "服务名称/主讲导读") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "活动状态 -1.已取消 0.未进行 1.已进行 2.已完成") @RequestParam(value = "status", required = false) Integer status,
            @ApiParam(value = "活动开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "活动结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        if (StringUtils.isBlank(corpUid))
            throw new DescribeException("请选择公司");

        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        List<CaScheduleLesson> lessons = scheduleLessonService.getStoreLessons(corpUid, storeUid, keyword, status, beginDate, endDate, null);
        List<LessonVO> voList = new ArrayList<>();
        int firstStartRow = 1;
        int firstEndRow = 0;
        // 需要合并的行号
        List<RowBean> firstRows = new ArrayList<>();
        // 需要合并的列号
        List<Integer> firstColumns = Lists.newArrayList(0, 1);

        if (CollectionUtils.isNotEmpty(lessons)) {
            List<String> lessonUids = lessons.stream().map(CaScheduleLesson::getLessonUid).collect(Collectors.toList());

            // 获取课时消耗统计
            List<CaCallNamesDto> callNamesList = callNameService.listByLessonUidIn(lessonUids);
            Map<List<Object>, Long> groupingMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(callNamesList)) {
                //  定义一个函数Function，该函数将元素对象映射到一个键的集合里
                Function<CaCallNamesDto, List<Object>> compositeKey =
                        callNames -> Arrays.asList(callNames.getLessonUid(), callNames.getHourType());
                // 多字段分组
                groupingMap = callNamesList.stream().collect(Collectors.groupingBy(compositeKey, Collectors.counting()));
            }

            Map<String, List<CaScheduleLesson>> lessonMap = lessons.stream().collect(Collectors.groupingBy(CaScheduleLesson::getTeacherUid));
            for (Map.Entry<String, List<CaScheduleLesson>> entry : lessonMap.entrySet()) {
                String teacherUidValue = entry.getKey();
                List<CaScheduleLesson> lessonList = entry.getValue();

                firstEndRow += lessonList.size();
                // 合并必须包含2个或更多单元格
                if (firstStartRow != firstEndRow)
                    firstRows.add(new RowBean(firstStartRow, firstEndRow));
                firstStartRow += lessonList.size();

                int lessonNum = lessonList.size();

                for (CaScheduleLesson lesson : lessonList) {
                    LessonVO lessonVO = new LessonVO();
                    lessonVO.setLessonNum(lessonNum);
                    lessonVO.setStoreName(lesson.getStoreName());
                    lessonVO.setTeachDate(lesson.getTeachDate() + " " + lesson.getBeginTime() + "-" + lesson.getEndTime());
                    lessonVO.setWeekName(lesson.getWeekName());
                    lessonVO.setClassName(lesson.getClassName());
                    lessonVO.setProductName(lesson.getProductName());
                    lessonVO.setStageName(lesson.getStageName());
                    lessonVO.setRoomName(lesson.getRoomName());
                    lessonVO.setTeacherName(lesson.getTeacherName());
                    lessonVO.setStudentNum(lesson.getStudentNum() + lesson.getStudentTempNum());
                    lessonVO.setReachNum(lesson.getReachNum() + lesson.getLateNum() + lesson.getNoHourNum());
                    lessonVO.setNotReachNum(lesson.getAskLeaveNum() + lesson.getNotReachNum());
                    lessonVO.setCloseStaffName(lesson.getCloseStaffName());
                    if (null != lesson.getCloseTime())
                        lessonVO.setCloseTime(DateUtil.getDefaultTimeStr(lesson.getCloseTime()));

                    // 课时消耗类型统计
                    lessonVO.setPayNum(NepUtil.nullToZero(groupingMap.get(Arrays.asList(lesson.getLessonUid(), 1))));
                    lessonVO.setGiftNum(NepUtil.nullToZero(groupingMap.get(Arrays.asList(lesson.getLessonUid(), 2))));
                    lessonVO.setExpNum(NepUtil.nullToZero(groupingMap.get(Arrays.asList(lesson.getLessonUid(), 3))));
                    lessonVO.setAuditionNum(NepUtil.nullToZero(groupingMap.get(Arrays.asList(lesson.getLessonUid(), 4))));
                    lessonVO.setFreeNum(NepUtil.nullToZero(groupingMap.get(Arrays.asList(lesson.getLessonUid(), 0))));
                    lessonVO.setNoHourNum(NepUtil.nullToZero(groupingMap.get(Arrays.asList(lesson.getLessonUid(), -1))));

                    // 加入导出列表
                    voList.add(lessonVO);
                }
            }
        }

        String fileName = "活动记录" + beginDate + "至" + endDate;
        ExcelHandler.exportMergeExcel(response, voList, LessonVO.class, fileName, "活动记录", firstRows, firstColumns);
    }


    @ApiOperation(value = "导出自营门店已完成的活动记录并计算课时费（人事）")
    @PostMapping(value = "/exportSelfStores", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportSelfStores(
            HttpServletResponse response,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid", required = false) String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid", required = false) String storeUid,
            @ApiParam(value = "服务名称/主讲导读") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        List<String> storeUidList = null;
//        if (StringUtils.isBlank(storeUid))
//        {
//            storeUidList = Lists.newArrayList(
//                    AccountUtil.WKLS_UID, AccountUtil.QHY_UID, AccountUtil.LHY_UID, AccountUtil.SXMD_UID,
//                    AccountUtil.SJGG_UID, AccountUtil.BLXB_UID, AccountUtil.LHTJ_UID, AccountUtil.SMLT_UID,
//                    AccountUtil.BHYT_UID, AccountUtil.ASMG_UID, AccountUtil.WHC_UID
//            );
//        }

        if (StringUtils.isBlank(corpUid) && StringUtils.isBlank(storeUid))
            throw new DescribeException("请选择公司或门店");

        List<CaScheduleLesson> lessons = scheduleLessonService.getStoreLessons(corpUid, storeUid, keyword, 2, beginDate, endDate, storeUidList);
        if (CollectionUtils.isEmpty(lessons))
            throw new DescribeException("没有查询到数据");

        // 按导读uid、导读姓名分组，获取有序的map
        Function<CaScheduleLesson, List<String>> teacherKey = vo -> Arrays.asList(vo.getTeacherUid(), vo.getTeacherName());
        Map<List<String>, List<CaScheduleLesson>> teacherLessonMap = lessons.stream()
                .collect(Collectors.groupingBy(teacherKey, LinkedHashMap::new, Collectors.toList()));

        // 获取已完成的活动uid集合
        List<String> lessonUids = lessons.stream().map(CaScheduleLesson::getLessonUid).collect(Collectors.toList());

        // 按活动uid、课时消耗类型，多属性分组
        List<CaCallNamesDto> callList = callNameService.listByLessonUidIn(lessonUids);
        Map<List<Object>, List<CaCallNamesDto>> groupingCallMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(callList)) {
            //  定义一个函数Function，该函数将元素对象映射到一个键的集合里
            Function<CaCallNamesDto, List<Object>> compositeKey = call -> Arrays.asList(call.getLessonUid(), call.getHourType());
            // 多属性分组
            groupingCallMap = callList.stream().collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
        }

        // 只查询体验课消的订单信息
        String expType = EnumType.OrderType.EXP.getType();
        List<String> orderCodeList = callList.stream()
                .filter(call -> StringUtils.isNotBlank(call.getOrderCode()) && StringUtils.isNotBlank(call.getServiceUid())
                        && StringUtils.isNotBlank(call.getOrderType()) && call.getOrderType().equals(expType))
                .map(CaCallNamesDto::getOrderCode)
                .collect(Collectors.toList());
        Map<String, CmorderDto> orderMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(orderCodeList)) {
            List<CmorderDto> cmorderDtos = cmordersService.dotListByOrderCodeIn(orderCodeList);
            orderMap = cmorderDtos.stream().collect(Collectors.toMap(CmorderDto::getOrderCode, Function.identity()));
        }

        // 统计总计费金额和点名的活动消耗类型
        List<LessonVoV3> voList = new ArrayList<>();
        for (Map.Entry<List<String>, List<CaScheduleLesson>> entry : teacherLessonMap.entrySet()) {
            List<String> teacherKeyList = entry.getKey();
            String teacherUid = teacherKeyList.get(0);
            String teacherName = teacherKeyList.get(1);
            List<CaScheduleLesson> lessonList = entry.getValue();
            // 总计费金额
            double amount = 0;
            List<LessonVoV3> newLessonVoList = new ArrayList<>();
            for (CaScheduleLesson lesson : lessonList) {
                LessonVoV3 lessonVO = new LessonVoV3();
                lessonVO.setTeacherUid(teacherUid);
                lessonVO.setTeacherName(lesson.getTeacherName());
                lessonVO.setLessonCnt(lessonList.size());
                lessonVO.setStoreName(lesson.getStoreName());
                lessonVO.setTeachDate(lesson.getTeachDate() + " " + lesson.getBeginTime() + "-" + lesson.getEndTime());
                lessonVO.setWeekName(lesson.getWeekName());
                lessonVO.setClassName(lesson.getClassName());
                lessonVO.setProductName(lesson.getProductName());
                lessonVO.setStageName(lesson.getStageName());
                lessonVO.setRoomName(lesson.getRoomName());
                lessonVO.setStudentNum(lesson.getStudentNum() + lesson.getStudentTempNum());
                lessonVO.setReachNum(lesson.getReachNum() + lesson.getLateNum() + lesson.getNoHourNum());
                lessonVO.setNotReachNum(lesson.getAskLeaveNum() + lesson.getNotReachNum());
                lessonVO.setCloseStaffName(lesson.getCloseStaffName());
                if (null != lesson.getCloseTime())
                    lessonVO.setCloseTime(DateUtil.getDefaultTimeStr(lesson.getCloseTime()));

                // 已完成活动的消耗统计
                // 正价
                int payNum = 0;
                String payMember = "";
                List<CaCallNamesDto> payList = groupingCallMap.get(Arrays.asList(lesson.getLessonUid(), 1));
                if (CollectionUtils.isNotEmpty(payList)) {
                    payNum = payList.size();
                    payMember = payList.stream().map(CaCallNamesDto::getNewMemberName).collect(Collectors.joining(","));
                }
                lessonVO.setPayNum(payNum);
                lessonVO.setPayMember(payMember);

                // 赠送
                int giftNum = 0;
                String giftMember = "";
                List<CaCallNamesDto> giftList = groupingCallMap.get(Arrays.asList(lesson.getLessonUid(), 2));
                if (CollectionUtils.isNotEmpty(giftList)) {
                    giftNum = giftList.size();
                    giftMember = giftList.stream().map(CaCallNamesDto::getNewMemberName).collect(Collectors.joining(","));
                }
                lessonVO.setGiftNum(giftNum);
                lessonVO.setGiftMember(giftMember);

                // 体验
                int expNum = 0;
                String expMember = "";
                List<CaCallNamesDto> expList = groupingCallMap.get(Arrays.asList(lesson.getLessonUid(), 3));
                List<CmorderDto> expOrderList = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(expList)) {
                    expNum = expList.size();
                    expMember = expList.stream().map(CaCallNamesDto::getNewMemberName).collect(Collectors.joining(","));

                    for (CaCallNamesDto call : expList) {
                        CmorderDto cmorderDto = orderMap.get(call.getOrderCode());
                        if (cmorderDto != null)
                            expOrderList.add(cmorderDto);
                    }
                }
                lessonVO.setExpNum(expNum);
                lessonVO.setExpMember(expMember);

                // 试听
                int auditionNum = 0;
                String auditionMember = "";
                List<CaCallNamesDto> auditionList = groupingCallMap.get(Arrays.asList(lesson.getLessonUid(), 4));
                if (CollectionUtils.isNotEmpty(auditionList)) {
                    auditionNum = auditionList.size();
                    auditionMember = auditionList.stream().map(CaCallNamesDto::getNewMemberName).collect(Collectors.joining(","));
                }
                lessonVO.setAuditionNum(auditionNum);
                lessonVO.setAuditionMember(auditionMember);

                // 免费
                int freeNum = 0;
                String freeMember = "";
                List<CaCallNamesDto> freeList = groupingCallMap.get(Arrays.asList(lesson.getLessonUid(), 0));
                if (CollectionUtils.isNotEmpty(freeList)) {
                    freeNum = freeList.size();
                    freeMember = freeList.stream().map(CaCallNamesDto::getNewMemberName).collect(Collectors.joining(","));
                }
                lessonVO.setFreeNum(freeNum);
                lessonVO.setFreeMember(freeMember);

                // 课时消耗结束未扣
                int noHourNum = 0;
                String noHourMember = "";
                // 未到
                int noReachNum = 0;
                String noReachMember = "";
                List<CaCallNamesDto> noHourList = groupingCallMap.get(Arrays.asList(lesson.getLessonUid(), -1));
                if (CollectionUtils.isNotEmpty(noHourList)) {
                    List<CaCallNamesDto> noConsumeList = new ArrayList<>();
                    List<CaCallNamesDto> noReachList = new ArrayList<>();
                    for (CaCallNamesDto callNames : noHourList) {
                        if (callNames.getCallStatus().equals(1) || callNames.getCallStatus().equals(2) || callNames.getCallStatus().equals(-1))
                            noConsumeList.add(callNames);
                        if (callNames.getCallStatus().equals(3) || callNames.getCallStatus().equals(4))
                            noReachList.add(callNames);
                    }

                    if (CollectionUtils.isNotEmpty(noConsumeList)) {
                        noHourNum = noConsumeList.size();
                        noHourMember = noConsumeList.stream().map(CaCallNamesDto::getNewMemberName).collect(Collectors.joining(","));
                    }
                    if (CollectionUtils.isNotEmpty(noReachList)) {
                        noReachNum = noReachList.size();
                        noReachMember = noReachList.stream().map(CaCallNamesDto::getNewMemberName).collect(Collectors.joining(","));
                    }
                }
                lessonVO.setNoHourNum(noHourNum);
                lessonVO.setNoHourMember(noHourMember);
                lessonVO.setNoReachNum(noReachNum);
                lessonVO.setNoReachMember(noReachMember);

                // 正价会员计费
                lessonVO.setPayAmount(ScheduleUtil.lessonPayCharge(lesson.getProjectUid(), payNum));
                // 赠送会员计费
                lessonVO.setGiftAmount(ScheduleUtil.lessonGiftCharge(giftNum));
                // 体验会员计费
                if (expNum > 0)
                    lessonVO.setExpAmount(ScheduleUtil.lessonExpAmount(expOrderList));
                else
                    lessonVO.setExpAmount(0d);
                // 累加总计费金额
                amount = DoubleUtil.sum(amount, lessonVO.getPayAmount());
                amount = DoubleUtil.sum(amount, lessonVO.getGiftAmount());
                amount = DoubleUtil.sum(amount, lessonVO.getExpAmount());

                // 加入导出列表
                newLessonVoList.add(lessonVO);
            }

            // 添加总计费金额
            for (LessonVoV3 voV3 : newLessonVoList) {
                voV3.setAmount(amount);
            }
            voList.addAll(newLessonVoList);
        }

        // 按导读username和总计费金额，多属性分组并排序
        LinkedHashMap<List<Object>, List<LessonVoV3>> lessonVoMap = new LinkedHashMap<>();
        if (CollectionUtils.isNotEmpty(voList)) {
            //  定义一个函数Function，该函数将元素对象映射到一个键的集合里
            Function<LessonVoV3, List<Object>> compositeKey = vo -> Arrays.asList(vo.getTeacherUid(), vo.getTeacherName(), vo.getAmount());
            // 多属性、排序分组
            lessonVoMap = voList.stream()
                    .sorted(Comparator.comparing(LessonVoV3::getAmount).reversed())
                    .collect(Collectors.groupingBy(compositeKey, LinkedHashMap::new, Collectors.toList()));
        }

        // 设置合并单元格
        int firstStartRow = 1;
        int firstEndRow = 0;
        // 需要合并的行号
        List<RowBean> firstRows = new ArrayList<>();
        // 需要合并的列号
        List<Integer> firstColumns = Lists.newArrayList(0, 1, 2);
        // 排序后的导出集合
        List<LessonVoV3> sortVoList = new ArrayList<>();

        for (Map.Entry<List<Object>, List<LessonVoV3>> entry : lessonVoMap.entrySet()) {
            List<LessonVoV3> list = entry.getValue();

            int size = list.size();
            firstEndRow += size;
            // 合并必须包含2个或更多单元格
            if (firstStartRow != firstEndRow)
                firstRows.add(new RowBean(firstStartRow, firstEndRow));
            firstStartRow += size;

            sortVoList.addAll(list);
        }

        String fileName = "自营门店活动记录" + beginDate + "至" + endDate;
        ExcelHandler.exportMergeExcel(response, sortVoList, LessonVoV3.class, fileName, "导读活动记录", firstRows, firstColumns);
    }


    @ApiOperation(value = "按月份导出自营门店已完成活动的课时费用")
    @PostMapping(value = "/exportSelfStoresConsumeAmount", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportSelfStoresConsumeAmount(
            HttpServletResponse response,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate
    ) throws Exception {

        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate)) {
            // 获取本月的第一天和最后一天
            Date monthMinDate = DateUtil.getMonthMinDate();
            Date monthMaxDate = DateUtil.getMonthMaxDate();
            beginDate = DateUtil.getDefaultTime2DateStr(monthMinDate);
            endDate = DateUtil.getDefaultTime2DateStr(monthMaxDate);
        }

        // 门店uid集合
        List<String> storeUidList = Arrays.asList(
                AccountUtil.WKLS_UID, AccountUtil.QHY_UID, AccountUtil.LHY_UID, AccountUtil.SXMD_UID,
                AccountUtil.SJGG_UID, AccountUtil.SSMG_UID, AccountUtil.WHDD_UID
        );

        // 1.正价 2.赠送 3.体验 4.试听
        List<Integer> hourTypes = Arrays.asList(1, 2);
        List<CaCallNames> list = callNameService.consumeListBySelfStore(storeUidList, hourTypes, beginDate, endDate);
        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("没有查询到数据");

        // 获取两个日期之间的所有月份
        String beginDateYM = StringUtils.substringBeforeLast(beginDate, "-");
        String endDateYM = StringUtils.substringBeforeLast(endDate, "-");
        List<String> monthList = DateUtil.getMonthsBetweenDates(beginDateYM, endDateYM);

        // 表格头部列的数据
        List<List<String>> headList = new ArrayList<>();
        // 表格第一列默认是门店名称
        headList.add(Collections.singletonList("门店名称"));
        // 表格按月份添加头部列
        for (String month : monthList) {
            headList.add(Collections.singletonList(month));
        }
        // 表格内的数据
        List<List<Object>> dataList = new ArrayList<>();

        // 将日期2024-01-01转为2024-01
        SimpleDateFormat format = new SimpleDateFormat(DateUtil.DEFAULT_YEAR_MONTH_FORMAT1);
        for (CaCallNames callNames : list) {
            String teachDate = callNames.getTeachDate();
            // yyyy-MM-dd 转 yyyy-MM
            Date date = DateUtil.parseDate(teachDate);
            String formatDate = format.format(date);
            callNames.setTeachDate(formatDate);
        }

        Map<String, List<CaCallNames>> storeUidMap = list.stream().collect(Collectors.groupingBy(CaCallNames::getStoreUid));
        for (Map.Entry<String, List<CaCallNames>> listEntry : storeUidMap.entrySet()) {
            String storeUidKey = listEntry.getKey();
            List<CaCallNames> storeList = listEntry.getValue();
            String storeName = storeList.get(0).getStoreName();

            Map<String, List<CaCallNames>> teachDateMap = storeList.stream().collect(Collectors.groupingBy(CaCallNames::getTeachDate, LinkedHashMap::new, Collectors.toList()));

            List<Object> data = new ArrayList<>();
            data.add(storeName);

            // 循环月份
            for (String month : monthList) {
                double payAmount = 0d;
                double giftAmount = 0d;
                List<CaCallNames> teachDateList = teachDateMap.get(month);
                if (CollectionUtils.isNotEmpty(teachDateList)) {
                    // 会员活动记录按活动课分组
                    Map<String, List<CaCallNames>> lessonUidList = teachDateList.stream().collect(Collectors.groupingBy(CaCallNames::getLessonUid));
                    for (Map.Entry<String, List<CaCallNames>> entry : lessonUidList.entrySet()) {
                        String key = entry.getKey();
                        List<CaCallNames> value = entry.getValue();

                        Map<Integer, List<CaCallNames>> hourTypeList = value.stream().collect(Collectors.groupingBy(CaCallNames::getHourType));
                        for (Map.Entry<Integer, List<CaCallNames>> hourEntry : hourTypeList.entrySet()) {
                            Integer key1 = hourEntry.getKey();
                            List<CaCallNames> value1 = hourEntry.getValue();
                            int size = value1.size();
                            if (key1.equals(1)) {
                                // 正价
                                String projectUid = value1.get(0).getProjectUid();
                                payAmount = DoubleUtil.sum(payAmount, ScheduleUtil.lessonPayCharge(projectUid, size));
                            } else if (key1.equals(2)) {
                                // 赠送
                                giftAmount = DoubleUtil.sum(giftAmount, ScheduleUtil.lessonGiftCharge(size));
                            } else {
                                System.out.println("未知的课消类型:" + key1);
                            }
                        }
                    }
                    double amount = DoubleUtil.sum(payAmount, giftAmount);
                    data.add(amount);
                } else {
                    data.add(0);
                }
            }

            dataList.add(data);
        }

        // 导出授权码
        String fileName = "门店课消费用";
        EasyExcel.write(ExcelHandler.getOutputStream(fileName, response))
                .head(headList).sheet("门店课消费用")
                .doWrite(dataList);
    }

}